#include "MathFunction.h"

namespace STC_calc {

FArgument::FArgument(const std::string& str)
{
	if (Counter::can_convert(str))
	{
		make_val(str);
		return;
	}
    if (can_be_constant(str))
    {
        make_const(str);
        return;
    }
	if (can_be_variable(str))
	{
        make_var(str);
		return;
	}
	make_func(str);
}

FArgument::FArgument(const FArgument& that)
{
    this->var = that.var;
    this->constant = that.constant;
    this->value = that.value;
    this->func = that.func;
    this->arg_type = that.arg_type;
}
void FArgument::operator =(const FArgument& that)
{
    this->var = that.var;
    this->constant = that.constant;
    this->value = that.value;
    this->func = that.func;
    this->arg_type = that.arg_type;
}
bool FArgument::operator ==(const FArgument& that)
{
    if (that.arg_type != this->arg_type) return false;

    if (this->arg_type == Enums::variable) return that.var == this->var;
    if (this->arg_type == Enums::function) return that.func == this->func;
    if (this->arg_type == Enums::value) return that.value == this->value;
    if (this->arg_type == Enums::constant) return that.constant == this->constant;
}
bool FArgument::operator !=(const FArgument& that)
{
    return !(this==that);
}


void FArgument::make_const(const std::string& str)
{
    var = nullptr;
    constant = Config::get_constant(str);
    value = 0;
    func = nullptr;
    arg_type = Enums::constant;
}
void FArgument::make_var(const std::string& str)
{
    var = Config::get_variable(str);
    constant = nullptr;
	value = 0;
	func = nullptr;
	arg_type = Enums::variable;
}
void FArgument::make_func(const std::string& str)
{
	std::shared_ptr ptr = std::make_shared<MathFunction>(str);
	func = ptr;
	value = 0;
	var = nullptr;
    constant = nullptr;
	arg_type = Enums::function;
}
void FArgument::make_val(const std::string& str)
{
	value = strtold(str.c_str(), NULL);
	var = nullptr;
	func = nullptr;
    constant = nullptr;
	arg_type = Enums::value;
}
bool FArgument::can_be_variable(const std::string& str)
{
    return Config::is_var(str);
}
bool FArgument::can_be_constant(const std::string &str)
{
    return Config::is_const(str);
}
std::string FArgument::cut_var_name(const std::string& str)
{
	std::string ret = str.substr(1, str.length() - 2);
	return ret;
}
FArgument::~FArgument()
{

}
long double FArgument::operator()()
{
	switch (arg_type)
	{
		case Enums::value: return value;
		case Enums::variable: return (*var)();
		case Enums::function: return (*func)();

		default: throw(RuntimeErrorClass("Error: arg_type in FArgument is not defined", Enums::fatal));
	}
}

}
